/**
 *  Copyright 2012 Antoine RADET
 *
 *   This file is part of Film Collection.
 *
 *   Film Collection is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Film Collection is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Film Collection.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * \file movie.c
 * \brief Functions for movies management
 * \author Antoine RADET
 */

#include <ctype.h>      /* tolower() */
#include <stdlib.h>     /* malloc(), ... */
#include <stdio.h>      /* stderr, fprintf() */
#include <stdarg.h>     /* va_list, va_arg,... */
#include <string.h>     /* strcpy(), strlen(),... */
#include "../Source_Files/movie.h"

/* movie title conversion for reading and opening operations */
char * convert_filename (char * movieName);

/* Get a characters string from a movie save file */
static char * get_char_from_save(FILE * save, int *len);

//////////////////////////////////////////////////////////////////////
//                      Exported functions                          //
//////////////////////////////////////////////////////////////////////

/**
 * \fn Movie * movie_new (char * name)
 * \brief Allocate a new movie and initialize it
 * \param[in]  name    Movie's title
 * \return A pointer to the Movie created, NULL if a problem occured.
 */
Movie * movie_new(void) {
    Movie *newFilm = NULL;

    if( (newFilm = (Movie *) malloc(sizeof(Movie))) == NULL ) {
        fprintf(stderr, "[Movie_new] : Error while trying to allocate a new movie \n");
        exit(EXIT_FAILURE);
    }
    if( (newFilm->synopsis = (char *) calloc(2, sizeof(char))) == NULL) {
        fprintf(stderr, "[Movie new] : Error while trying to allocate memory for a synopsis");
        exit(EXIT_FAILURE);
    }

    movie_init(newFilm);

    return newFilm;
}

/**
 * \fn void movie_delete (Movie *ptrMov)
 * \brief Free the memory allocated to a Movie
 * \param[in, out]  ptrMov  Pointer for the movie to delete
 */
void movie_delete (Movie *ptrMov)
{
    free(ptrMov->synopsis);
    free(ptrMov);
}

/**
 * \fn void movie_init (Movie *ptrMov)
 * \brief Initialize every field to 0, "" or NULL
 * \param[in, out]  ptrMov  Movie to initialize
 */
void movie_init (Movie *ptrMov)
{
    strcpy(ptrMov->title, " ");
    ptrMov->year = 0;
    strcpy(ptrMov->director, " ");
    strcpy(ptrMov->mainActors, " ");
    ptrMov->genre = UNKNOWN;
    ptrMov->duration = 0;
    strcpy(ptrMov->languages, " ");
    strcpy(ptrMov->subtitles, " ");
    ptrMov->media = DVD;
    ptrMov->synopsis = " ";
    strcpy(ptrMov->imagePath, " ");
    strcpy(ptrMov->allocineLink, " ");
}

/**
 * \fn short movie_setInformation (Movie *ptrFilm, MovieInformation info, ...)
 * \brief Set one or more information about a film
 * \param[in, out]  ptrFilm Pointer to the film that will be modified
 * \param[in]       info    Type of the first movie information
 * \return 1 if success, -1 if error.
 *
 * WARNING : The last MovieInformation must be END
 *           When a field contains several data, separate them with a semi-colon
 *           Give the length of the synopsis before the characters string
 *
 * Call example : movie_setInformation (&film, TITLE, "Banana powa!", MAIN_ACTORS, "Toto ; Mister banana", SYNOPSIS, 6, "Coucou", END);
 */
short movie_setInformation (Movie *ptrFilm, MovieInformation info, ...)
{
    MovieInformation currentInfoType = info;
    va_list listPointer;
    char * ptrString = NULL;   /* Pointer to the string we want to update */

    /* Initialize the list pointer */
    va_start(listPointer, info);

    while( currentInfoType != END) {
        ptrString = NULL;

        switch(currentInfoType) {
            case TITLE    : ptrString = ptrFilm->title;
                            break;

            case DIRECTOR : ptrString = ptrFilm->director;
                            break;

            case SYNOPSIS : ptrFilm->synopsis = (char *) calloc(va_arg(listPointer, int), sizeof(char));
                            strcpy(ptrFilm->synopsis, va_arg(listPointer, char *));
                            break;

            case MAIN_ACTORS    : ptrString = ptrFilm->mainActors;
                                  break;

            case LANGUAGES      : ptrString = ptrFilm->languages;
                                  break;

            case SUBTITLES      : ptrString = ptrFilm->subtitles;
                                  break;

            case IMG_PATH   :   ptrString = ptrFilm->imagePath;
                                break;

            case LINK       :   ptrString = ptrFilm->allocineLink;
                                break;

            case YEAR       :   ptrFilm->year = va_arg(listPointer, int);
                                break;

            case DURATION   :   ptrFilm->duration = va_arg(listPointer, int);
                                break;

            case GENRE :    ptrFilm->genre = va_arg(listPointer, Genre);
                            break;

            case MEDIA :    ptrFilm->media = va_arg(listPointer, Media);
                            break;

            default :   return -1;
                        break;
        }

        if(ptrString != NULL)
            strcpy(ptrString, va_arg(listPointer, char *));

        /* Update the information type */
        currentInfoType = va_arg(listPointer, MovieInformation);

    }   /* while( currentInfoType != END) */

    return 1;
}

/**
 * \fn int movie_saveMovie (Movie *ptrMov)
 * \brief Save the current movie information into a binary file
 * \param   ptrMov     Pointer to the film that will be saved
 * \param   savePath   Path for saving the file
 *
 * \return EXIT_SUCESS if save ok, EXIT_FAILURE otherwise.
 */
int movie_saveMovie (Movie *ptrMov, char *savePath)
{
    FILE * save = NULL;    /* Pointer to the file */

    /* Try to open/create the file */
    if( (save = fopen(savePath, "wb")) == NULL) {
       fprintf(stderr, "Error while trying to open or create file %s", savePath);
       return EXIT_FAILURE;
    }

    /* Save movie data excepted synopsis */
    fwrite(ptrMov, sizeof(Movie), 1, save);

    /* Save synopsis */
    if(ptrMov->synopsis != NULL)
        fprintf(save, ptrMov->synopsis);

    fclose(save);

    return EXIT_SUCCESS;
}

/**
 * \fn Movie * movie_openMovie (char * name)
 * \brief Open a movie information file
 * \param[in]   name     Name of the film
 *
 * \return A pointer to the movie if open success, NULL otherwise.
 *
 * Data are always saved in ../data/Movies/[movie_title].movie
 */
Movie * movie_openMovie (char * filename)
{
    FILE *openFile = NULL;
    Movie *openMovie = NULL;
    int lenSynopsis = 0;
    char *strSynopsis = NULL;

    /* Try to open the file */
    if( (openFile = fopen(filename, "rb")) == NULL) {
       fprintf(stderr, "Error while trying to open file : %s : ", filename);
       return NULL;
    }

    openMovie = (Movie *) malloc(sizeof(Movie));

    /*  Get movie information excepted the synopsis */
    fread(openMovie, sizeof(Movie), 1, openFile);

    /* Get the synopsis */
    strSynopsis =  get_char_from_save(openFile, &lenSynopsis);
    openMovie->synopsis = (char *) calloc(lenSynopsis, sizeof(char));
    strcpy(openMovie->synopsis, strSynopsis);

    fclose(openFile);

    return openMovie;
}

/**
 * \fn char * convert_filename (char * movieName)
 * \brief Convert the movie name into a the correct filename format
 * \param[in]       name        Movie's title
 * \param[in, out]  filename    Conversion result
 */
char * convert_filename (char * movieName)
{
    char *convert = NULL, *filename = NULL;
    int i = 0, j = 0;

    convert = (char *) calloc(strlen(movieName), sizeof(char));

    /* Delete every space character in movie title and replace it by _ */
    do{
       if(movieName[i] != ' ')
           convert[j++] = tolower(movieName[i]);
       else if(movieName[i-1] != ' ')
           convert[j++] = '_';
    }while(movieName[i++] != '\0');

    filename = (char *) calloc(strlen(convert) + strlen(MOVIE_PATH) + strlen(MOVIE_EXT), sizeof(char));

    /* Create the correct datapath */
    strcat(filename, MOVIE_PATH);
    strcat(filename, convert);
    strcat(filename, MOVIE_EXT);

    return filename;
}


//////////////////////////////////////////////////////////////////////
//                      Local functions                             //
//////////////////////////////////////////////////////////////////////

/**
 * \fn static char * get_char_from_save(FILE * save, int *len)
 * \brief Get a character string from a movie save file
 * \param[in, out]  save    Save file
 * \param[in, out]  len     Pointer to the number for characters read
 *
 * IMPORTANT : structure movie must have been read before using this function
 */
static char * get_char_from_save(FILE * save, int *len)
{
    int i=0, savePos;
    char * getString;

    savePos = ftell(save);
    fseek(save, 0, SEEK_END);
    *len = ftell(save) - savePos;   /* Evaluate the maximum size of the character string */
    fseek(save, savePos, SEEK_SET);

    getString = (char *) calloc((*len + 1), sizeof(char));
    *len = 0;

    do{
        fread(&(getString[i]), sizeof(char), 1, save);
        (*len) ++;
    }while(getString[i++] != '\0');

    getString = (char *) realloc(getString, (*len + 1) * sizeof(char) );  /* Resize the string to the correct size */

    return getString;
}
